/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package agent.teavitus.behaviour;

import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.util.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;

import agent.Location;
import agent.keskkonna.KeskkonnaAgent;
import agent.ontology.AlertOntology;
import agent.ontology.LocationOntology;
import agent.params.LocationParam;
import agent.params.PassangerParam;
import agent.teavitus.TeavitusAgent;
import agent.teekonna.TeekonnaAgent;
import agent.types.AlertLocationType;
import agent.util.AgentUtil;

/**
 * 
 * @author margus
 */
public class TeavitusCyclicBehaviour extends CyclicBehaviour {

	private static final long serialVersionUID = 1L;
	private static final Logger LOG = Logger
			.getJADELogger(TeavitusCyclicBehaviour.class.getName());
	private static final int USER_ALERT_COUNT = 3;
	private Map<String, Alert> alertHolder = new ConcurrentHashMap<>();

	public TeavitusCyclicBehaviour(TeavitusAgent myAgent) {
		super(myAgent);
	}

	@Override
	public void action() {
		ACLMessage msg = myAgent.receive();
		if (msg == null) {
			block();
		} else {
			try {
				// päring tuleb keskkonna kontrollerist
				if (msg.getSender().equals(
						AgentUtil.createLocalAid(KeskkonnaAgent.class))) {
					String id = msg.getReplyWith();

					LOG.info("Sõnum keskkonna kontrollerilt ID: " + id);
					LOG.info(msg.toString());

					Alert alert = alertHolder.get(id);
					alert.setLocation(new Location(
							msg.getUserDefinedParameter(LocationParam.LOCATION_GPS_N
									.name()),
							msg.getUserDefinedParameter(LocationParam.LOCATION_GPS_E
									.name())));
					forwardAlert();
				} else {

					AlertOntology alertType = AlertOntology.valueOf(msg
							.getOntology());
					String content = msg.getContent();
					String id = UUID.randomUUID().toString();
					Alert alert = new Alert(
							id,
							alertType,
							AlertLocationType.valueOf(msg
									.getUserDefinedParameter(LocationParam.LOCATION_TYPE
											.name())), content);
					alertHolder.put(id, alert);

					queryLocation(msg, alert);
				}
			} catch (Exception ex) {
				LOG.log(Level.SEVERE, STATE_BLOCKED, ex);
			}
		}
	}

	private void queryLocation(ACLMessage msg, Alert alert) {

		ACLMessage locationMsg = new ACLMessage(ACLMessage.INFORM);
		locationMsg.addReceiver(AgentUtil.createLocalAid(KeskkonnaAgent.class));
		locationMsg.setOntology(LocationOntology.GPS.name());
		locationMsg
				.addUserDefinedParameter(PassangerParam.PASSANGER_ID.name(),
						msg.getUserDefinedParameter(PassangerParam.PASSANGER_ID
								.name()));
		locationMsg.setReplyWith(alert.getId());

		myAgent.send(locationMsg);
	}

	private void forwardAlert() {

		LOG.info("Kontrollime kas on vaja teavitus edasi suunata teekonna kontrollerile");

		Map<String, Long> alertCount = new HashMap<>();
		List<String> sended = new ArrayList<>();

		for (Alert alert : alertHolder.values()) {
			ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
			String key = alert.getAlertType().name()
					+ alert.getLocation().toString();
			Long count = alertCount.get(key);
			count = count == null ? 1 : ++count;
			alertCount.put(key, count);
			if (count == USER_ALERT_COUNT) {
				sended.add(key);
				msg.setContent(alert.getAdditionalInfo());
				msg.setOntology(LocationOntology.GPS.name());
				msg.addUserDefinedParameter(
						LocationParam.LOCATION_GPS_E.name(), alert
								.getLocation().getGpsE());
				msg.addUserDefinedParameter(
						LocationParam.LOCATION_GPS_N.name(), alert
								.getLocation().getGpsN());
				msg.addReceiver(AgentUtil.createLocalAid(TeekonnaAgent.class));
				this.myAgent.send(msg);
				LOG.info("Teavitust tüübiga " + alert.getAlertType().name()
						+ " asukohaga " + alert.getLocation().toString()
						+ " edastati teekonna kontrollerile");
			} else {
				LOG.info("Teavitust tüübiga " + alert.getAlertType().name()
						+ " asukohaga " + alert.getLocation().toString()
						+ " ei edastata");
			}
		}

		if (sended.isEmpty()) {
			return;
		}

		// eemaldame daadetud teavitused
		for (Iterator<Entry<String, Alert>> iterator = alertHolder.entrySet()
				.iterator(); iterator.hasNext();) {
			Entry<String, Alert> entry = iterator.next();
			Alert alert = entry.getValue();
			String key = alert.getAlertType().name()
					+ alert.getLocation().toString();
			if (sended.contains(key)) {
				iterator.remove();
			}
		}
	}
}
